package com.zbb.order.service.Impl;

import com.zbb.base.model.Result;
import com.zbb.order.config.DelayedQueueConfig;
import com.zbb.order.mapper.*;
import com.zbb.order.model.dto.ImageDto;
import com.zbb.order.model.dto.InsertOrderDto;
import com.zbb.order.model.po.*;
import com.zbb.order.rabbitmq.MyCallBack;
import com.zbb.order.service.InsertOrderService;
import com.zbb.order.util.SecurityUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.UUID;

@Service
@Slf4j
public class InsertOrderServiceImpl implements InsertOrderService, RabbitTemplate.ConfirmCallback ,
        RabbitTemplate.ReturnCallback {

    @Autowired
    PictureMapper pictureMapper;

    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    OrderInitiateMapper orderInitiateMapper;

    @Autowired
    OrderDetailsMapper orderDetailsMapper;

    @Autowired
    LabelRelationMapper labelRelationMapper;

    @Autowired
    OrderSnapshotMapper orderSnapshotMapper;


    @Autowired
    private MyCallBack myCallBack;
    //依赖注入 rabbitTemplate 之后再设置它的回调对象
    @PostConstruct
    private void init() {
        rabbitTemplate.setConfirmCallback(this);
        /**
         * true：
         * 交换机无法将消息进行路由时，会将该消息返回给生产者
         * false：
         * 如果发现消息无法进行路由，则直接丢弃
         */
        rabbitTemplate.setMandatory(true);
        //设置回退消息交给谁处理
        rabbitTemplate.setReturnCallback(this);
    }


    @Transactional
    @Override
    public Result insertOrder(InsertOrderDto insertOrderDto) {
        /**
         * 1.新增新发订单信息
         * 2.新增订单详情信息
         * 4.新增图片关联信息
         * 5.新增标签关联信息
         * 6.生成订单快照
         */
        LocalDateTime createTime = LocalDateTime.now();
        LocalDateTime updateTime = LocalDateTime.now();
        User user = SecurityUtil.getUser();
//        1.新增新发订单信息
         String initiateId = UUID.randomUUID().toString();
         String startTime =  insertOrderDto.getStartTime().substring(0,19).replace("T", " ");
         String endTime = insertOrderDto.getEndTime().substring(0,19).replace("T", " ");
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        OrderInitiate orderInitiate = new OrderInitiate(initiateId,insertOrderDto.getSchoolId(),insertOrderDto.getCampusId(),user.getId(),user.getUserName(),insertOrderDto.getTitle(),insertOrderDto.getContent(),0,0,LocalDateTime.parse(startTime,df),LocalDateTime.parse(endTime,df));
        int insert = orderInitiateMapper.insert(orderInitiate);
//        2.新增订单详情
        String detailId = UUID.randomUUID().toString();
        OrderDetails orderDetails = new OrderDetails(detailId,initiateId,user.getId(),user.getUserName(),insertOrderDto.getTitle(),insertOrderDto.getContent(),insertOrderDto.getAddress(),LocalDateTime.parse(startTime,df),LocalDateTime.parse(endTime,df),createTime,updateTime);
        int insert1 = orderDetailsMapper.insert(orderDetails);
        //3生成订单快照
        String snapshotId = UUID.randomUUID().toString();
        OrderSnapshot orderSnapshot = new OrderSnapshot(snapshotId,user.getId(),null,initiateId,insertOrderDto.getTitle(),insertOrderDto.getContent(),LocalDateTime.parse(startTime,df),LocalDateTime.parse(endTime,df),LocalDateTime.now(),LocalDateTime.now(),0,0);
        orderSnapshotMapper.insert(orderSnapshot);
//        4.新增图片关联信息
        int i =1;
        for (ImageDto image:insertOrderDto.getFileList()) {
            Picture picture = new Picture(UUID.randomUUID().toString(),detailId,snapshotId,image.getUrl(),i++,createTime,updateTime);
            pictureMapper.insert(picture);
        }
        //5新增标签关联信息
        for (Integer labelId:insertOrderDto.getLabels()){
            LabelRelation labelRelation = new LabelRelation(UUID.randomUUID().toString(),labelId,detailId,initiateId,createTime,updateTime);
            labelRelationMapper.insert(labelRelation);
        }

        // 指定时间
        ZonedDateTime dateTime = ZonedDateTime.parse(insertOrderDto.getEndTime());
        ZonedDateTime now = ZonedDateTime.now();
        Duration duration = Duration.between(now, dateTime);
        long diff = duration.toMillis();

        CorrelationData correlationData=new CorrelationData(initiateId);
        log.info("当前时间：{}，发送正确延迟消息时间为：{}，Id为{}",new Date().toString(), diff, initiateId);
        //rabbitmq生产延迟消息
        rabbitTemplate.convertAndSend(DelayedQueueConfig.DELAYED_EXCHANGE_NAME, DelayedQueueConfig.DELAYED_ROUTING_KEY, initiateId, msg ->{
            msg.getMessageProperties().setDelay((int) diff);
            return msg;
        },correlationData);
        return Result.ok();
    }

    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        String id = correlationData != null ? correlationData.getId() : "";
        if (ack) {
            log.info("交换机收到消息确认成功, id:{}", id);
        } else {
            log.error("消息 id:{}未成功投递到交换机,原因是:{}", id, cause);
        }
    }
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String
            exchange, String routingKey) {
        log.info("消息:{}被服务器退回，退回原因:{}, 交换机是:{}, 路由 key:{}",
                new String(message.getBody()),replyText, exchange, routingKey);
    }
}
